﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using FarseerGames.FarseerPhysics;
using FarseerGames.FarseerPhysics.Dynamics;
using FarseerGames.FarseerPhysics.Collisions;
using FarseerGames.FarseerPhysics.Factories;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using FolderData;

namespace Folder
{
    public class EventManager
    {

        GameplayScreen _gamePlayScreen;
        private Dictionary<OnCollisionEvent, CollisionEventHandler> EventDic;

        public EventManager(GameplayScreen gamePlayScreen)
        {
            this._gamePlayScreen = gamePlayScreen;
            InitEventDic();
            BindEvent(_gamePlayScreen.map);
        }

        private void InitEventDic()
        {
            EventDic = new Dictionary<OnCollisionEvent, CollisionEventHandler>();

            EventDic.Add(OnCollisionEvent.None, OnCollisionEvent_None);
            EventDic.Add(OnCollisionEvent.ToCheckPoint, OnCollisionEvent_ToCheckPoint);
            EventDic.Add(OnCollisionEvent.StageEnd, OnCollisionEvent_StageEnd);
        }

        private void BindEvent(Map map)
        {
            foreach (Substance s in map.Substances.Values)
            {
                s.Geom.OnCollision += EventDic[s.OnCollision];
                if (s is Item)
                {
                    if ((s as Item).Kind == Item.ItemKind.KEY)
                    {
                        s.Geom.OnCollision += OnCollision_Key;
                    }
                }
                else if (s is Character)
                {
                    if(s != map.Player)
                        s.Geom.OnCollision += OnCollision_Monster;
                }
            }

            map.Player.Geom.OnCollision += OnCollision_Player;
            map.Player.Geom.OnSeparation += OnSeparation_Player;
        }

        public bool OnCollisionEvent_None(Geom g1, Geom g2, ContactList contactList)
        {
            return true;
        }

        public bool OnCollisionEvent_ToCheckPoint(Geom g1, Geom g2, ContactList contactList)
        {
            return false;
        }

        public bool OnCollisionEvent_StageEnd(Geom g1, Geom g2, ContactList contactList)
        {
            _gamePlayScreen.StageClear();
            return false;
        }

        //점프 가능 여부를 확인한다.

        public bool Jumpable
        {
            get { if (jumpableTimer < JumpableTime) return true; else return false; }
        }
        public float jumpableTimer = 0.0f;
        public static readonly float JumpableTime = 200f;

        //플레이어와 다른 물체가 충돌했을 때.
        //특정 조건을 만족하면 점프할 수 있게 한다.
        public bool OnCollision_Player(Geom geom1, Geom geom2, ContactList contactList)
        {
            Character player = geom1.Tag as Character;
            if (geom2.Tag is Terrain)
            {
                //체크 포인트를 지나갔을 때.
                var t = (Terrain)geom2.Tag;
                if (t.Kind == Terrain.TerrainKind.MONSTER_BLOCK)
                {
                    return false;
                }
                if (t.Kind == Terrain.TerrainKind.CHECK_POINT)
                {
                    if (t == _gamePlayScreen.CheckPoint)
                        return false;
                    if (_gamePlayScreen.CheckPoint != null)
                        _gamePlayScreen.CheckPoint.Activation = false;
                    _gamePlayScreen.CheckPoint = t;
                    _gamePlayScreen.CheckPoint.Activation = true;
                    return false;
                }
                //가시와 충돌합니다.
                else if (t.Kind == Terrain.TerrainKind.BRAMBLES)
                {
                    _gamePlayScreen.CheckPointState = CheckPointState.Init;
                }
            }
            else if (geom2.Tag is Character)
            {
                _gamePlayScreen.CheckPointState = CheckPointState.Init;
            }

            foreach (Contact c in contactList)
            {
                //조건 1. 평행하게 붙어 있되 플레이어가 대상 물체 위에 있을 경우
                //조건 2. 플레이어와 충돌 대상 물체 사이의 각도가 일정 수준 이하일 경우(평평할 경우)
                if ((c.Normal.X < 0.5 && c.Normal.X > -0.5) && geom1.Position.Y < geom2.Position.Y)
                {
                    jumpableTimer = 0.0f;
                    return true;
                }
            }
            return true;
        }

        
        public void OnSeparation_Player(Geom geom1, Geom geom2)
        {
            /*
            Character player = geom1.Tag as Character;
            if (player.CollidedGeom.Contains(geom2))
            {
                player.CollidedGeom.Remove(geom2);
                if (player.CollidedGeom.Count == 0)
                    Jumpable = false;
            }
             * */
        }





        //캐릭터와 같은 충돌 적용이 필요하다.
        public bool OnCollision_Monster(Geom geom1, Geom geom2, ContactList contactList)
        {
            Character monster = geom1.Tag as Character;

            foreach (Contact c in contactList)
            {
                if (geom2.Tag is Terrain)
                {
                    //체크 포인트를 지나갔을 때.
                    var t = (Terrain)geom2.Tag;
                    if (t.Kind == Terrain.TerrainKind.CHECK_POINT)
                    {
                        return false;
                    }
                }

                //조건 1. 평행하게 붙어 있되 플레이어가 대상 물체 위에 있을 경우
                //조건 2. 플레이어와 충돌 대상 물체 사이의 각도가 일정 수준 이하일 경우(평평할 경우)
                //if ((c.Normal.X < 0.5 && c.Normal.X > -0.5) && geom1.Position.Y < geom2.Position.Y)
                if(monster.Body.LinearVelocity.Length() > 100)
                {
                    if (monster.CurDirection == Character.Direction.LEFT)
                    {
                        monster.Body.LinearVelocity = new Vector2(-1*monster.Speed, 0);
                    }
                    else if (monster.CurDirection == Character.Direction.RIGHT)
                    {
                        monster.Body.LinearVelocity = new Vector2(monster.Speed, 0);
                    }
                }
                else
                {
                    if (monster.CurDirection == Character.Direction.LEFT)
                    {
                        monster.CurDirection = Character.Direction.RIGHT;
                        monster.Body.LinearVelocity = new Vector2(monster.Speed, 0);
                    }
                    else
                    {
                        monster.CurDirection = Character.Direction.LEFT;
                        monster.Body.LinearVelocity = new Vector2(-1 * monster.Speed, 0);
                    }

                }
            }
            return true;
        }

        public bool OnCollision_Key(Geom geom1, Geom geom2, ContactList contactList)
        {
            if (geom2.Tag is Terrain)
            {
                //문과 출돌했을 경우 activation을 바꾼다.
                if ((geom2.Tag as Terrain).Kind == Terrain.TerrainKind.GATE)
                {
                    (geom2.Tag as Terrain).Activation = false;
                    (geom1.Tag as Item).Activation = false;
                }
                //임시 패치. CollisionCategory를 정리하기 전까지 임시로 사용한다.
                else if ((geom2.Tag as Terrain).Kind == Terrain.TerrainKind.CHECK_POINT)
                    return false;
            }
            return true;
        }
    }
}
